package base

import (
	"archive/zip"
	"bytes"
	"cgs-server/server"
	"cgs-server/server/model"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

// 生成包装 data 和 user 的容器
func GenerateDataUserModel(data interface{}, r *http.Request) *model.DataUserModel {
	user, _ := GetCurrentUser(r)
	dataUserModel := model.DataUserModel{
		Data: data,
		User: user,
	}
	return &dataUserModel
}

func GetCurrentUser(r *http.Request) (*model.User, error) {
	sysUser, err := server.GetCurrentUser(r)
	if err != nil {
		return nil, err
	}
	user := &model.User{}
	if sysUser != nil {
		ConvertSysUser(sysUser, user)
	}
	return user, nil
}

// 生成 TenantId 随机数
func GenerateTenantId() string {
	rand.Seed(time.Now().Unix())
	var b strings.Builder
	for i := 0; i < 6; i++ {
		b.WriteString(strconv.Itoa(rand.Intn(10)))
	}
	return b.String()
}

// ReadZipFile zip 工具
func ReadZipFile(data []byte) ([]*model.ZipFileData, error) {
	reader := bytes.NewReader(data)
	return ReadZip(reader, int64(len(data)))
}

// ReadZip 解压zip文件到对象
func ReadZip(reader io.ReaderAt, size int64) ([]*model.ZipFileData, error) {
	zipData := []*model.ZipFileData{}
	r, _ := zip.NewReader(reader, size)
	for _, f := range r.File {
		name := f.Name

		// 乱码问题
		if f.Flags == 0 {
			// 如果标志位(f.Flags)为0，则默认是本地编码，默认为 gbk
			i := bytes.NewReader([]byte(f.Name))
			decoder := transform.NewReader(i, simplifiedchinese.GB18030.NewDecoder())
			content, _ := ioutil.ReadAll(decoder)
			name = string(content)
		} else {
			// 如果标志位是 1 << 11 也就是2048，则是utf-8编码
			name = f.Name
		}

		info := f.FileInfo()
		if info.IsDir() { // dir

		} else { // file
			read, err := f.Open()
			if err != nil {
				return nil, err
			}
			m, err := ioutil.ReadAll(read)
			if err := read.Close(); err != nil {
				return nil, err
			}

			zipData = append(zipData, &model.ZipFileData{Name: name, Body: m})
		}
	}
	return zipData, nil
}

func ZipFile(dataArr []*model.ZipFileData) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	w := zip.NewWriter(buf)
	defer w.Close()
	for _, file := range dataArr {
		f, err := w.Create(file.Name)
		if err != nil {
			return nil, err
		}
		_, err = f.Write(file.Body)
		if err != nil {
			return nil, err
		}
	}
	return buf, nil
}

func ZipFileToBuffer(dir string) (*bytes.Buffer, error) {
	// check dir
	stat, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return nil, fmt.Errorf("%v is not exist", dir)
	}
	if !stat.IsDir() {
		return nil, fmt.Errorf("%v is not a dir", dir)
	}

	dir = strings.ReplaceAll(dir, "/", string(filepath.Separator))

	var fileData []*model.ZipFileData
	// func to create zip file
	walkFunc := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if path == dir || strings.HasSuffix(path, ".zip") { // The first path of filepath.Walk is always the root.
			return nil
		}
		trimPath := strings.TrimPrefix(path, dir)
		if info.IsDir() { // dir

		} else { // file
			byteData, err := ioutil.ReadFile(path)
			if err != nil {
				return err
			}
			fileData = append(fileData, &model.ZipFileData{
				Name: trimPath,
				Body: byteData,
			})
		}
		return nil
	}

	// walk all the directories and files in the dir
	if err := filepath.Walk(dir, walkFunc); err != nil {
		return nil, err
	}

	return ZipFile(fileData)
}
